﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using InkFx.WinControl.Core;
using InkFx.WinControl.Utils;

namespace InkFx.WinControl
{
    /// <summary>
    /// 提供一个可用来创建其他控件的空控件。
    /// </summary>
    [ToolboxItem(false)]
    public class XIDEFrame : XIDEUserControl
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public XIDEFrame()
        {
            this.Name = XIDEPanel.NewName("ideFrame");
            if(!InkFx.WinControl.Form.IsDesignMode) base.Dock = DockStyle.Fill;

            //this.Visible = false;
            Tools.LogDebug(string.Format("XIDEFrame 创建: Name='{0}' Type='{1}' ", this.Name, Tools.GetKnowTypeName(this.GetType())));
        }


        #region  字 段 属 性

        /// <summary>
        /// 内部字段
        /// </summary>
        protected Image m_Icon = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected string m_Text = string.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected string m_ToolTipText = string.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly object m_DestroyLocker = new object();

        /// <summary>
        /// 图标
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public virtual Image Icon
        {
            get { return m_Icon; }
            set { m_Icon = value; }
        }

        /// <summary>
        /// 标题
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string Text
        {
            get { return m_Text; }
            set
            {
                m_Text = (value ?? string.Empty).Trim();
                var group = this.FindGroup();
                if (group != null) { group.ResetRect(); }
            }
        }

        /// <summary>
        /// 气泡提示
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public virtual string ToolTipText
        {
            get
            {
                if (Tools.IsNullOrWhiteSpace(m_ToolTipText)) return m_Text;
                return m_ToolTipText;
            }
            set { m_ToolTipText = (value ?? string.Empty).Trim(); }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示是否显示该控件及其所有父控件。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new bool Visible
        {
            get { return base.Visible; }
            set { base.Visible = value; }
        }

        #endregion


        #region  函 数 改 写

        /// <summary>
        /// 引发 System.Windows.Forms.Control.SizeChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            ////如果控件的可显示区域太小, 则控件将不显示 
            ////之所以要这样, 是因为设置了 IDEPanel 的 WS_CLIPCHILDREN 后, 如果 此IDEFrame中是一个 ListView 控件, 
            ////当 ListView 的显示高度很小时, ListView 会发生消息的死循环, 用 Spy++拦截发现: ListView 死循环的是 NM_CUSTOMDRAW 消息
            //var size = this.Size;
            //var visible = size.Width >= 5 && size.Height >= 5;
            //this.Visible = visible;

            base.OnSizeChanged(e);
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.VisibleChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (this.Visible)
            {
                var level = Win32API.GetParentLevel(this);
                if (level >= 16) { Win32API.ReSetWindowPos(this.Handle); }
            }
        }

        /// <summary>
        /// 返回包含 System.ComponentModel.Component 的名称的 System.String（如果有）。不应重写此方法。
        /// </summary>
        /// <returns>包含 System.ComponentModel.Component 的名称的 System.String（如果有）；如果 System.ComponentModel.Component 未命名，则为 null。</returns>
        public override string ToString()
        {
            return base.ToString();
        }

        #endregion


        #region  销 毁 逻 辑

        /// <summary>
        /// 获取 当前XIDEFrame 在关闭时 的 资源释放模式
        /// <para>必须改写本函数: </para>
        /// <para>　> 如果返回 Dispose, 则会完全释放所有资源</para>
        /// <para>　> 如果返回 Hidden, 则不会释放资源, 仅仅只是从UI上移除</para>
        /// </summary>
        /// <returns>Frame 的 资源释放模式</returns>
        public virtual XIDEFrameReleaseMode GetReleaseMode()
        {
            throw new InvalidOperationException("XIDEFrame的子类 必须继承改写 GetReleaseMode() 函数, 以明确 XIDEFrame 的释放模式");
        }

        /// <summary>
        /// 查找当前 XIDEFrame 所属的 IDEPanel
        /// </summary>
        /// <returns></returns>
        public virtual XIDEPanel FindIDEPanel()
        {
            var group = this.FindGroup();
            return group == null ? null : group.IDEPanel;
        }
        /// <summary>
        /// 查找当前 XIDEFrame 所属的 XIDEGroup
        /// </summary>
        /// <returns></returns>
        public virtual XIDEGroup FindGroup()
        {
            var parent = this.Parent;
            if (parent is XIDEGroup) { return (XIDEGroup)parent; }
            return null;
        }
        /// <summary>
        /// 查找当前 XIDEFrame 所属的 XIDEPage
        /// </summary>
        /// <returns></returns>
        public virtual XIDEPage FindPage()
        {
            var group = this.FindGroup();
            if (group == null || group.ListPage == null) return null;
            foreach (var page in group.ListPage) { if (page != null && page.Frame == this) { return page; } }
            return null;
        }



        /// <summary>
        /// 在延迟 10秒 后, 调用 当前Frame 的 TryDestroyCore() 函数, 执行 当前Frame 的销毁逻辑 
        /// </summary>
        public void TryDestroy()
        {
            Task.SetUIDelay(this, m_DestroyLocker.GetHashCode(), () => TryDestroyCore(), 10000);
        }
        /// <summary>
        /// 执行 当前Frame 的 销毁逻辑
        /// <para>如果 当前Frame 的 Parent 属性为 null, 则函数不会执行任何代码</para>
        /// </summary>
        /// <returns>如果函数没有执行 当前Frame 的释放操作, 则返回false</returns>
        protected virtual bool TryDestroyCore()
        {
            if (this.Parent != null) return false;

            try
            {
                var mode = this.GetReleaseMode();
                if (mode == XIDEFrameReleaseMode.Dispose) { this.DisposeFrame(); }
                return true;
            }
            catch (Exception ex)
            {
                var msg = string.Format("销毁 XIDEFrame 发生错误: \r\n\r\nName='{0}' \r\nText='{1}' \r\nType='{2}' \r\nMsg='{3}' ", this.Name, this.Text, Tools.GetKnowTypeName(this.GetType()), ex.Message);
                MessageBox.Show(msg + "\r\n\r\n" + ex); return false;
            }
        }

        /// <summary>
        /// 释放由 System.Windows.Forms.ButtonBase 占用的非托管资源，还可以另外再释放托管资源。
        /// </summary>
        /// <param name="disposing">为 true 则释放托管资源和非托管资源；为 false 则仅释放非托管资源。</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                base.Dispose(disposing);
                Tools.LogDebug(string.Format("XIDEFrame 销毁: Name='{0}' Text='{1}' Type='{2}' ", this.Name, this.Text, Tools.GetKnowTypeName(this.GetType())));
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "可忽略的偶发错误"); }
        }

        /// <summary>
        /// 调用 Dispose() 执行销毁操作
        /// </summary>
        protected virtual void DisposeFrame()
        {
            this.Dispose();
        }

        #endregion


        #region  布 局 XML

        /// <summary>
        /// XIDEPanel 面板 可以保存布局状态, 并在程序重启时 恢复布局状态
        /// <para>在 保存布局 和 恢复布局 时, 如果需要将 当前 XIDEFrame 的 额外信息保存下来, 则需要改写本函数</para>
        /// <para>代码示例: node["Path"] = "D:\Temp.sql"</para>
        /// </summary>
        /// <param name="node"></param> 
        public virtual void SaveLayoutNode(XIDEPanel.LayoutNode node)
        {
            
        }
        /// <summary>
        /// XIDEPanel 面板 可以保存布局状态, 并在程序重启时 恢复布局状态
        /// <para>在 保存布局 和 恢复布局 时, 如果需要将 当前 XIDEFrame 的 额外信息保存下来, 则需要改写本函数</para>
        /// <para>代码示例: string path = node["Path"]; this.LoadSql(path); </para>
        /// </summary>
        /// <param name="node"></param>
        public virtual void LoadLayoutNode(XIDEPanel.LayoutNode node)
        {
            
        }

        #endregion

    }

    /// <summary>
    /// XIDEFrame 在关闭时 的 资源释放模式
    /// </summary>
    [Serializable]
    public enum XIDEFrameReleaseMode
    {
        /// <summary>
        /// 当 XIDEFrame 关闭时, 不会释放资源, 仅仅只是从UI上移除
        /// </summary>
        Hidden = 0,
        /// <summary>
        /// 当 XIDEFrame 关闭时, 会完全释放所有资源
        /// </summary>
        Dispose = 1,
    }


    /// <summary>
    /// 提供一个可用来创建其他控件的空控件。
    /// </summary>
    [ToolboxItem(false)]
    public class XIDETempFrame : XIDEFrame
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public XIDETempFrame()
        {
            base.Text = "临时Frame";
            base.BackColor = Color.FromArgb(150, Color.HotPink);
        }

        /// <summary>
        /// 获取 当前XIDEFrame 在关闭时 的 资源释放模式
        /// <para>必须改写本函数: </para>
        /// <para>　> 如果返回 Dispose, 则会完全释放所有资源</para>
        /// <para>　> 如果返回 Hidden, 则不会释放资源, 仅仅只是从UI上移除</para>
        /// </summary>
        /// <returns>Frame 的 资源释放模式</returns>
        public override XIDEFrameReleaseMode GetReleaseMode()
        {
            return XIDEFrameReleaseMode.Dispose;
        }
    }
}
